package com.duowan.cms.common.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 *  只能解压缩zip文件，不能解压rar文件
 */
public class ZipUtil {

	/**
	 * 将指定目录压缩
	 * 
	 * @param basePath
	 *            指定的目录的路径
	 * @param zipname
	 *            压缩后的存放路径
	 * @throws Exception
	 */
	public static void zipFile(String basePath, String zipname) throws Exception {
		ZipEntry ze = null;
		byte[] buffer = new byte[1024];
		int readLen = 0;
		ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipname));
		for (File file : getFiles(new File(basePath))) {
			ze = new ZipEntry(getRelativePath(file, basePath));
			ze.setSize(file.length());
			ze.setTime(file.lastModified());
			zos.putNextEntry(ze);
			InputStream in = new BufferedInputStream(new FileInputStream(file));
			while ((readLen = in.read(buffer, 0, 1024)) != -1) {
				zos.write(buffer, 0, readLen);
			}
			in.close();
		}
		zos.close();

	}

	/**
	 * 将给定的压缩文件进行解压，放到指定目录
	 * 
	 * @param zipFilename
	 *            需要解压缩的文件
	 * @param dir
	 *            解压后文件存放的目录
	 */
	public static void upZipFile(String zipFilename, String dir) throws Exception {
		File targetDirFile = new File(dir);
		if (!targetDirFile.exists()) {
			targetDirFile.mkdirs();
		}
		ZipInputStream zin = new ZipInputStream(new FileInputStream(zipFilename));
		ZipEntry ze = null;
		byte[] buf = new byte[1024];
		while ((ze = zin.getNextEntry()) != null) {
			File file = getRealFile(dir, ze.getName());
			if (ze.isDirectory()) {
				if (!file.exists()) {
					file.mkdirs();
				}
			}else{
				OutputStream os = new BufferedOutputStream(new FileOutputStream(file));
				int readLen = 0;
				while ((readLen = zin.read(buf, 0, 1024)) != -1) {
					os.write(buf, 0, readLen);
				}
				os.close();
			}
		}
		zin.close();
	}

	/**
	 * 根据给定的目录返回该文件夹下所有的文件（包括子目录） 如果给定的是文件则返回该文件
	 * 
	 * @param file
	 *            给定的文件目录
	 * @return 所有文件的列表
	 */
	private static  List<File> getFiles(File fileDir) {
		List<File> listFiles = new LinkedList<File>();
		// 判断给定的fileDir是否为文件，如果是则直接返回
		if (fileDir.isFile()) {
			listFiles.add(fileDir);
			return listFiles;
		}
		// 如果是目录则遍历该目录
		File[] files = fileDir.listFiles();
		for (File file : files) {
			if (file.isFile()) {
				listFiles.add(file);
			} else {
				// 对方法进行递归调用
				listFiles.addAll(getFiles(file));
			}
		}
		return listFiles;
	}

	/**
	 * 给定根目录，返回另一个文件名的相对路径，用于zip文件中的路径
	 * 
	 * @param file
	 *            实际的文件名
	 * @param baseDir
	 *            根目录
	 * @return
	 */
	private static String getRelativePath(File file, String baseDir) {
		File base = new File(baseDir);
		String filename = file.getName();
		while (true) {
			file = file.getParentFile();
			if (file == null)
				break;
			if (file.equals(base))
				break;
			else
				filename = file.getName() + "/" + filename;
		}
		return filename;
	}

	/**
	 * 给定根目录，返回一个相对路径所对应的实际文件名.
	 * 
	 * @param baseDir 指定根目录
	 * @param absFileName 相对路径名，来自于ZipEntry中的name
	 * @return java.io.File 实际的文件
	 */
	private static  File getRealFile(String baseDir, String absFileName) {
		// 判断是否有下级目录,如果没有则将该文件直接new出来
		String[] dirs = absFileName.split("/");
		File ret = new File(baseDir);
		// 有下级目录则先创建目录，再创建文件
		if (dirs.length > 1) {
			for (int i = 0; i < dirs.length - 1; i++) {
				ret = new File(ret, dirs[i]);
			}
			if (!ret.exists())
				ret.mkdirs();
			ret = new File(ret, dirs[dirs.length - 1]);
			return ret;
		}
		return new File(ret, absFileName);
	}
	
	public static void main(String[] args) throws Exception {
	    String basePath = System.getProperty("user.dir");
	    String zipFilename = basePath+File.separator+"test.zip";
	    System.out.println(System.getProperty("user.dir"));
	    String dir=basePath;
        ZipUtil.upZipFile(zipFilename, dir);
    }
	
}
